#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "telephoneBook.h"
#include "contactPerson.h"

struct telephoneBook
{
    elementType *array;
    int capacity;
    int size;

    void (*freePtr)(elementType);
};

TBook *initTBook(int capacity, void (*freePtr)(elementType))
{
    TBook *a = (TBook *)malloc(sizeof(TBook));
    if (NULL == a)
    {
        perror("malloc error!\n");
        return NULL;
    }

    a->capacity = capacity;
    a->size = 0;
    a->array = (elementType *)malloc(sizeof(elementType) * a->capacity);
    if (NULL == a->array)
    {
        perror("malloc error!\n");
        free(a);
        return NULL;
    }
    a->freePtr = freePtr;

    return a;
}

void freeTBook(void *ptr)
{
    TBook *a = (TBook *)ptr;

    if (a)
    {
        if (a->array)
        {
            if (a->freePtr != NULL)
            {
                for (int i = 0; i < a->size; i++)
                {
                    a->freePtr(a->array[i]);
                }
            }

            free(a->array);
        }
        
        free(a);
    }
}

bool insertContact(TBook *a, elementType element)
{
    if (a->size >= a->capacity)
    {
        elementType *newArr = (elementType *)realloc(a->array, sizeof(elementType) * (a->capacity * 2));
        if (NULL == newArr)
        {
            perror("malloc error!\n");
            return false;
        }

        a->array = newArr;
        a->capacity *= 2;
    }

    a->array[a->size] = element;
    a->size++;

    return true;
}

elementType findContactPerson(TBook *a, elementType element, bool (*find)(elementType, elementType))
{
    if (NULL == a)
    {
        return NULL;
    }

    for (int i = 0; i < a->size; i++)
    {
        if (find(a->array[i], element) == true)
        {
            return a->array[i];
        }
    }

    return NULL;
}

elementType binarySerchContactPerson(TBook *a, elementType element, int (*find)(elementType, elementType))
{
    int leftIdx = 0;
    int rightIdx = a->size - 1;

    while (leftIdx <= rightIdx)
    {
        int midIdx = (leftIdx & rightIdx) + ((leftIdx ^ rightIdx) >> 1);

        // 比中间值小，往左边找
        if (find(a->array[midIdx], element) > 0)
        {
            // 左半边找
            rightIdx = midIdx - 1;
        }
        else if (find(a->array[midIdx], element) < 0)
        {
            leftIdx = midIdx + 1;
        }
        else
        {
            // 找到了
            return a->array[midIdx];
        }
    }

    // 没找到
    return NULL;
}

void delContactPerson(TBook *a, elementType element, bool (*find)(elementType, elementType))
{
    if (NULL == a)
    {
        return;
    }

    int idx = 0;
    int numDeleted = 0;

    for (int i = 0; i < a->size; i++)
    {
        if (find(a->array[i], element) == true)
        {
            if (a->freePtr != NULL)
            {
                a->freePtr(a->array[i]);
            }
            
            numDeleted++;
        }
        else
        {
            a->array[i - numDeleted] = a->array[i];
        }
    }

    a->size -= numDeleted;
}

void printTBook(TBook *a, void (*print)(elementType))
{
    // printf("size = %d capacity = %d\n", a->size, a->capacity);

    for (int i = 0; i < a->size; i++)
    {
        print(a->array[i]);
    }

    printf("\n");
}

void insertSort(TBook *a, bool (*sort)(elementType, elementType))
{
    for(int i = 0; i < a->size; i++)
    {
        int j = i;
        elementType tmp = a->array[i];
        for(; j > 0; j--)
        {
            if((sort(a->array[j - 1], tmp) > 0) == true)
            {
                a->array[j] = a->array[j - 1];
            }
            else
            {
                break;
            }
        }

        a->array[j] = tmp;
    }
}

void printAllMatches(TBook *a, elementType element, bool (*find)(elementType, elementType), bool (*sort)(elementType, elementType))
{
    if (NULL == a)
    {
        return;
    }

    bool found = false;

    insertSort(a, sort);

    for (int i = 0; i < a->size; i++)
    {
        if (find(a->array[i], element))
        {
            printCper(a->array[i]);
            found = true;
        }
    }

    if (!found)
    {
        printf("未找到匹配的联系人\n");
    }
}

void SaveBook(TBook *a,char *(*GetInfo)(void *))
{
    FILE *f = fopen("./book.txt", "w");
    if(f == NULL)
    {
        printf("文件打开失败!保存文件失败!\n");
        return;
    }

    for (int i = 0; i < a->size; i++)
    {
        char *s = GetInfo(a->array[i]);
        fprintf(f, "%s", s);
        free(s);
    }
    fclose(f);
}

void ReadFromBook(TBook *a,void*(*ptr)(char*,char*))
{
    FILE *f = fopen("./book.txt", "r");
    if (f == NULL)
    {
        printf("文件打开失败!保存文件失败!\n");
        return;
    }
    while(1)
    {
        char name[20];
        char tele[20];
        if(fscanf(f, "name=%s telephone=%s", name,tele) < 0)
        {
            break;
        }
        insertContact(a,ptr(name,tele));
        printf("%s %s\n",name,tele);
    }
    //关闭文件
    fclose(f);
}
